package com.zjsru.plan2024.oneday;

import java.util.*;

/**
 * 638. 大礼包
 *
 * @Author: cookLee
 * @Date: 2024-11-03
 */
public class ShoppingOffers {

    /**
     * 主
     * \
     * 输入：price = [2,5], special = [[3,0,5],[1,2,10]], needs = [3,2]
     * 输出：14
     * 解释：有 A 和 B 两种物品，价格分别为 ¥2 和 ¥5 。
     * 大礼包 1 ，你可以以 ¥5 的价格购买 3A 和 0B 。
     * 大礼包 2 ，你可以以 ¥10 的价格购买 1A 和 2B 。
     * 需要购买 3 个 A 和 2 个 B ， 所以付 ¥10 购买 1A 和 2B（大礼包 2），以及 ¥4 购买 2A 。
     * \
     * 输入：price = [2,3,4], special = [[1,1,0,4],[2,2,1,9]], needs = [1,2,1]
     * 输出：11
     * 解释：A ，B ，C 的价格分别为 ¥2 ，¥3 ，¥4 。
     * 可以用 ¥4 购买 1A 和 1B ，也可以用 ¥9 购买 2A ，2B 和 1C 。
     * 需要买 1A ，2B 和 1C ，所以付 ¥4 买 1A 和 1B（大礼包 1），以及 ¥3 购买 1B ， ¥4 购买 1C 。
     * 不可以购买超出待购清单的物品，尽管购买大礼包 2 更加便宜
     * \
     * @param args args
     */
    public static void main(String[] args) {
        ShoppingOffers shoppingOffers = new ShoppingOffers();
        List<Integer> price = Arrays.asList(2, 5);
        List<List<Integer>> special = Arrays.asList(Arrays.asList(3, 0, 5), Arrays.asList(1, 2, 10));
        List<Integer> needs = Arrays.asList(3, 2);
        System.out.println(shoppingOffers.shoppingOffers(price, special, needs));
    }

    Map<List<Integer>, Integer> memo = new HashMap<List<Integer>, Integer>();


    /**
     * 购物优惠
     *
     * @param price   价格
     * @param special 特殊
     * @param needs   需要
     * @return int
     */
    public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
        int len = price.size();
        //过滤不需要计算的礼包
        List<List<Integer>> filterSpecial = new ArrayList<>();
        for (List<Integer> sp:
             special) {
            int totalPrice = 0;
            int totalCount = 0;
            for (int i = 0; i < len; i++) {
                totalCount += sp.get(i);
                totalPrice += sp.get(i) * price.get(i);
            }
            //考虑优惠的礼包
            if(totalCount > 0 && totalPrice > sp.get(len)){
                filterSpecial.add(sp);
            }
        }
        return this.dfs(price,needs,filterSpecial,len);
    }

    private int dfs(List<Integer> price,List<Integer> curNeeds, List<List<Integer>> filterSpecial, int len) {
        if (!this.memo.containsKey(curNeeds)) {
            int minPrice = 0;
            for (int i = 0; i < len; ++i) {
                // 不购买任何大礼包，原价购买购物清单中的所有物品
                minPrice += curNeeds.get(i) * price.get(i);
            }
            for (List<Integer> curSpecial : filterSpecial) {
                int specialPrice = curSpecial.get(len);
                List<Integer> nxtNeeds = new ArrayList<Integer>();
                for (int i = 0; i < len; ++i) {
                    // 不能购买超出购物清单指定数量的物品
                    if (curSpecial.get(i) > curNeeds.get(i)) {
                        break;
                    }
                    nxtNeeds.add(curNeeds.get(i) - curSpecial.get(i));
                }
                if (nxtNeeds.size() == len) {
                    // 大礼包可以购买
                    minPrice = Math.min(minPrice, this.dfs(price, nxtNeeds, filterSpecial, len) + specialPrice);
                }
            }
            this.memo.put(curNeeds, minPrice);
        }
        return this.memo.get(curNeeds);
    }

}
